package com.jcompressor.faces.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

import org.apache.commons.lang.StringUtils;

import com.jcompressor.utils.RegexUtils;

/*
 * Copyright (c) 2011, Scott Carnett
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 * following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimerin the documentation and/or other materials provided with the distribution.
 * * Neither the name of jcompressor nor the names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @author Scott Carnett
 */
public class FacesUtils {
	
	public static final String EL_PATTERN = "\\#\\{(.*?)\\}";
	public static final String EL_PREFIX = "#{";
	public static final String EL_SUFFIX = "}";
	
	public static void assertValidContext(final FacesContext facesContext) {
		if (facesContext == null) {
			throw new FacesException("FacesContext cannot be null");
		}
		
		if (facesContext.getExternalContext() == null) {
			throw new FacesException("ExternalContext cannot be null");
		}
	}
	
	public static ValueExpression createValueExpression(final FacesContext facesContext, final String expression, final Class<?> type) {
		FacesUtils.assertValidContext(facesContext);
		return facesContext.getApplication().getExpressionFactory().createValueExpression(facesContext.getELContext(), expression, type);
	}
	
	public static List<UIComponent> getAllChildren(final List<UIComponent> children, final UIComponent component) {
		if ((component instanceof UIComponent) && (component.getChildren() != null)) {
			for (final UIComponent child : component.getChildren()) {
				children.add(child);
				FacesUtils.getAllChildren(children, child);
			}
			
			return children;
		}
		
		return null;
	}
	
	public static Object getExpressionValue(final FacesContext facesContext, final String expression, final Class<?> type) {
		return FacesUtils.createValueExpression(facesContext, expression, type).getValue(facesContext.getELContext());
	}
	
	public static Object getExpressionValue(final FacesContext facesContext, final ValueBinding binding) {
		FacesUtils.assertValidContext(facesContext);
		return ((binding == null) ? null : binding.getValue(facesContext));
	}
	
	public static String getExpressionValue(final UIComponent component, final FacesContext facesContext, final String attr, final String value) {
		if (StringUtils.isNotBlank(value)) {
			return value;
		}
		
		final Object obj = FacesUtils.getExpressionValue(facesContext, component.getValueBinding(attr));
		return ((obj != null) ? StringUtils.trimToEmpty((String)obj) : null);
	}
	
	public static List<String> getEls(final String str) {
		if (StringUtils.isBlank(str)) {
			return null;
		}
		
		final Pattern pattern = Pattern.compile(FacesUtils.EL_PATTERN);
		final Matcher matcher = pattern.matcher(str);
		if (matcher.find()) {
			final List<String> els = new ArrayList<String>();
			while (matcher.find()) {
				els.add(matcher.group());
			}
			
			return els;
		}
		
		return null;
	}
	
	public static boolean conainsEl(final String str) {
		return (FacesUtils.getEls(str) != null);
	}
	
	public static boolean isEl(final String str) {
		if (StringUtils.isBlank(str)) {
			return false;
		}
		
		return RegexUtils.compile(FacesUtils.EL_PATTERN).matcher(str).matches();
	}
	
	public static void pushComponentResourceToRoot(final FacesContext facesContext, final UIComponent component, final String target) {
		facesContext.getViewRoot().addComponentResource(facesContext, component, target);
	}
	
}